package org.leeloo.internal.core;

import java.util.List;

import junit.framework.TestCase;

import org.eclipse.debug.core.DebugException;
import org.eclipse.debug.core.ILaunch;
import org.eclipse.debug.core.model.IDebugTarget;
import org.eclipse.debug.core.model.IRegisterGroup;
import org.eclipse.debug.core.model.IThread;
import org.eclipse.debug.core.model.IVariable;
import org.eclipse.jdt.debug.core.IJavaClassType;
import org.eclipse.jdt.debug.core.IJavaFieldVariable;
import org.eclipse.jdt.debug.core.IJavaObject;
import org.eclipse.jdt.debug.core.IJavaReferenceType;
import org.eclipse.jdt.debug.core.IJavaStackFrame;
import org.eclipse.jdt.debug.core.IJavaThread;
import org.eclipse.jdt.debug.core.IJavaType;
import org.eclipse.jdt.debug.core.IJavaValue;
import org.eclipse.jdt.debug.core.IJavaVariable;
import org.eclipse.jface.action.Action;
import org.eclipse.jface.dialogs.IDialogConstants;
import org.eclipse.jface.dialogs.InputDialog;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.ui.IViewPart;
import org.leeloo.core.Tag;
import org.leeloo.core.TagService;
import org.leeloo.core.Tags;

public class EditNameActionTest extends TestCase {
    private Shell shell;
    private TagService tagService;
    private ObjectDescriptor descriptor;
    private IJavaObject javaObject;

    protected void setUp() throws Exception {
        super.setUp();

        shell = new Shell();
        tagService = new TagService();
        descriptor = new ObjectDescriptor();        
        javaObject = new JavaObjectStub();
    }

    protected void tearDown() throws Exception {
        if (shell != null && !shell.isDisposed()) {
            shell.dispose();
            shell = null;
        }

        super.tearDown();
    }

    /**
     * Asserts that if no previous name exists the user is prompted with an
     * empty dialog value.
     * 
     * @throws Exception
     */
    public void testRunNoPreviousName() throws Exception {
        //create a container with a value other than what is expected
        final String[] container = new String[1];
        container[0] = ""; 
        
        EditNameAction action = new EditNameAction() {
            protected TagService getTagService() {
                return tagService;
            }
            
            protected InputDialog getInputDialog(String name) {
                container[0] = name;
                
                InputDialog dialog = new InputDialog(shell, "", "", name, null);
                dialog.setBlockOnOpen(false);
                return dialog;
            }
            
            protected ObjectDescriptor getObjectDescriptor(IJavaObject object, IJavaStackFrame stackFrame) {
                //return a new object that doesn't have a name in the tagService
                return descriptor;
            }
            
            protected IJavaObject getJavaObject(ISelection selection) {
                return javaObject;
            }
            
            protected IJavaStackFrame getStackFrame(IViewPart viewPart) {
                return new JavaStackFrameStub();
            }
        };
        
        action.selectionChanged(new Action() {}, null);
        action.runWithEvent(null, null);
        assertNull(container[0]);
    }

    /**
     * Asserts that if a previous name exists it will be displayed to the user.
     * 
     * @throws Exception
     */
    public void testRunLoadPreviousName() throws Exception {
        final ObjectDescriptor descriptor = new ObjectDescriptor();
        final String tagValue = "moveable feast";
        tagService.put(descriptor, new Tag(Tags.NAME, tagValue));

        final String[] container = new String[1];
        
        EditNameAction action = new EditNameAction() {
            protected TagService getTagService() {
                return tagService;
            }
            
            protected InputDialog getInputDialog(String name) {
                container[0] = name;
                
                InputDialog dialog = new InputDialog(shell, "", "", name, null);
                dialog.setBlockOnOpen(false);
                return dialog;
            }
            
            protected ObjectDescriptor getObjectDescriptor(IJavaObject object, IJavaStackFrame stackFrame) {
                return descriptor;
            }
            
            protected IJavaStackFrame getStackFrame(IViewPart viewPart) {
                return new JavaStackFrameStub();
            }
            
            protected IJavaObject getJavaObject(ISelection selection) {
                return javaObject;
            }
        };
        
        action.selectionChanged(new Action(){}, null);
        action.runWithEvent(null, null);
        assertEquals(tagValue, container[0]);
    }

    /**
     * Asserts that when canceled the name is not saved.
     * 
     * @throws Exception
     */
    public void testRunCancel() throws Exception {
        final ObjectDescriptor descriptor = new ObjectDescriptor();
        String tagValue = "moveable feast";
        tagService.put(descriptor, new Tag(Tags.NAME, tagValue));
        
        final InputDialogStub dialog = new InputDialogStub(shell, "old man and the sea");
        dialog.returnCode = IDialogConstants.CANCEL_ID;
        
        EditNameAction action = new EditNameAction() {
            protected TagService getTagService() {
                return tagService;
            }
            
            protected InputDialog getInputDialog(String name) {
                return dialog;
            }
            
            protected ObjectDescriptor getObjectDescriptor(IJavaObject object, IJavaStackFrame stackFrame) {
                return descriptor;
            }
            
            protected IJavaStackFrame getStackFrame(IViewPart viewPart) {
                return new JavaStackFrameStub();
            }
            
            protected IJavaObject getJavaObject(ISelection selection) {
                return javaObject;
            }
        };
        
        action.selectionChanged(new Action() {}, null);
        action.runWithEvent(null, null);
        Tag tag = tagService.get(descriptor, Tags.NAME);
        assertEquals(tagValue, tag.getValue());
        assertEquals(1, dialog.openCount);
    }

    /**
     * Asserts that the entered name is saved.
     * 
     * @throws Exception
     */
    public void testRunSaveName() throws Exception {
        final ObjectDescriptor descriptor = new ObjectDescriptor();
        String tagValue = "moveable feast";
        tagService.put(descriptor, new Tag(Tags.NAME, tagValue));
        
        final InputDialogStub dialog = new InputDialogStub(shell, null);
        
        EditNameAction action = new EditNameAction() {
            protected TagService getTagService() {
                return tagService;
            }
            
            protected InputDialog getInputDialog(String name) {
                return dialog;
            }
            
            protected ObjectDescriptor getObjectDescriptor(IJavaObject object, IJavaStackFrame stackFrame) {
                return descriptor;
            }
            
            protected IJavaStackFrame getStackFrame(IViewPart viewPart) {
                return new JavaStackFrameStub();
            }
            
            protected IJavaObject getJavaObject(ISelection selection) {
                return javaObject;
            }
        };
        
        dialog.value = "old man and the sea";
        
        action.selectionChanged(new Action() {}, null);
        action.runWithEvent(null, null);
        Tag tag = tagService.get(descriptor, Tags.NAME);
        assertEquals(dialog.value, tag.getValue());
        assertEquals(1, dialog.openCount);
    }
    
    private static class JavaObjectStub implements IJavaObject {

        public IJavaFieldVariable getField(String name, boolean superField) throws DebugException {
            return null;
        }

        public IJavaFieldVariable getField(String name, String typeSignature) throws DebugException {
            return null;
        }

        public IJavaThread getOwningThread() throws DebugException {
            return null;
        }

        public IJavaThread[] getWaitingThreads() throws DebugException {
            return null;
        }

        public IJavaValue sendMessage(String selector, String signature, IJavaValue[] args, IJavaThread thread, boolean superSend) throws DebugException {
            return null;
        }

        public IJavaValue sendMessage(String selector, String signature, IJavaValue[] args, IJavaThread thread, String typeSignature) throws DebugException {
            return null;
        }

        public String getGenericSignature() throws DebugException {
            return null;
        }

        public IJavaType getJavaType() throws DebugException {
            return null;
        }

        public String getSignature() throws DebugException {
            return null;
        }

        public String getReferenceTypeName() throws DebugException {
            return null;
        }

        public String getValueString() throws DebugException {
            return null;
        }

        public IVariable[] getVariables() throws DebugException {
            return null;
        }

        public boolean hasVariables() throws DebugException {
            return false;
        }

        public boolean isAllocated() throws DebugException {
            return false;
        }

        public IDebugTarget getDebugTarget() {
            return null;
        }

        public ILaunch getLaunch() {
            return null;
        }

        public String getModelIdentifier() {
            return null;
        }

        public Object getAdapter(Class adapter) {
            return null;
        }
        
    }
    
    private static class JavaStackFrameStub implements IJavaStackFrame {

        public IJavaVariable findVariable(String variableName) throws DebugException {
            return null;
        }

        public List getArgumentTypeNames() throws DebugException {
            return null;
        }

        public IJavaClassType getDeclaringType() throws DebugException {
            return null;
        }

        public String getDeclaringTypeName() throws DebugException {
            return null;
        }

        public int getLineNumber(String stratum) throws DebugException {
            return 0;
        }

        public IJavaVariable[] getLocalVariables() throws DebugException {
            return null;
        }

        public String getMethodName() throws DebugException {
            return null;
        }

        public String getReceivingTypeName() throws DebugException {
            return null;
        }

        public IJavaReferenceType getReferenceType() throws DebugException {
            return null;
        }

        public String getSignature() throws DebugException {
            return null;
        }

        public String getSourceName() throws DebugException {
            return null;
        }

        public String getSourceName(String stratum) throws DebugException {
            return null;
        }

        public String getSourcePath() throws DebugException {
            return null;
        }

        public String getSourcePath(String stratum) throws DebugException {
            return null;
        }

        public IJavaObject getThis() throws DebugException {
            return null;
        }

        public boolean isConstructor() throws DebugException {
            return false;
        }

        public boolean isNative() throws DebugException {
            return false;
        }

        public boolean isObsolete() throws DebugException {
            return false;
        }

        public boolean isOutOfSynch() throws DebugException {
            return false;
        }

        public boolean isStaticInitializer() throws DebugException {
            return false;
        }

        public boolean isSynchronized() throws DebugException {
            return false;
        }

        public boolean isVarArgs() throws DebugException {
            return false;
        }

        public boolean supportsDropToFrame() {
            return false;
        }

        public boolean wereLocalsAvailable() {
            return false;
        }

        public int getCharEnd() throws DebugException {
            return 0;
        }

        public int getCharStart() throws DebugException {
            return 0;
        }

        public int getLineNumber() throws DebugException {
            return 0;
        }

        public String getName() throws DebugException {
            return null;
        }

        public IRegisterGroup[] getRegisterGroups() throws DebugException {
            return null;
        }

        public IThread getThread() {
            return null;
        }

        public IVariable[] getVariables() throws DebugException {
            return null;
        }

        public boolean hasRegisterGroups() throws DebugException {
            return false;
        }

        public boolean hasVariables() throws DebugException {
            return false;
        }

        public IDebugTarget getDebugTarget() {
            return null;
        }

        public ILaunch getLaunch() {
            return null;
        }

        public String getModelIdentifier() {
            return null;
        }

        public Object getAdapter(Class adapter) {
            return null;
        }

        public boolean canStepInto() {
            return false;
        }

        public boolean canStepOver() {
            return false;
        }

        public boolean canStepReturn() {
            return false;
        }

        public boolean isStepping() {
            return false;
        }

        public void stepInto() throws DebugException {            
        }

        public void stepOver() throws DebugException {
            
        }

        public void stepReturn() throws DebugException {            
        }

        public boolean canResume() {
            return false;
        }

        public boolean canSuspend() {
            return false;
        }

        public boolean isSuspended() {
            return false;
        }

        public void resume() throws DebugException {            
        }

        public void suspend() throws DebugException {
            
        }

        public boolean canTerminate() {
            return false;
        }

        public boolean isTerminated() {
            return false;
        }

        public void terminate() throws DebugException {
            
        }

        public boolean isFinal() throws DebugException {
            return false;
        }

        public boolean isPackagePrivate() throws DebugException {
            return false;
        }

        public boolean isPrivate() throws DebugException {
            return false;
        }

        public boolean isProtected() throws DebugException {
            return false;
        }

        public boolean isPublic() throws DebugException {
            return false;
        }

        public boolean isStatic() throws DebugException {
            return false;
        }

        public boolean isSynthetic() throws DebugException {
            return false;
        }

        public boolean canStepWithFilters() {
            return false;
        }

        public void stepWithFilters() throws DebugException {
            
        }

        public boolean canDropToFrame() {
            return false;
        }

        public void dropToFrame() throws DebugException {
        }
    }
    
    private static class InputDialogStub extends InputDialog {
        int openCount;
        String value;
        int returnCode = IDialogConstants.OK_ID;
        
        public InputDialogStub(Shell parentShell, String value) {
            super(parentShell, "", "", value, null);
            setBlockOnOpen(false);
        }
        
        public String getValue() {
            return value;
        }
        
        public int getReturnCode() {
            return returnCode;
        }
        
        public int open() {
            openCount++;
            
            return getReturnCode();
        }
    }
}
